package com.apgblogs.springbootstudy.config;

import com.apgblogs.springbootstudy.model.Authorities;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;

import javax.sql.DataSource;

/**
 * @author xiaomianyang
 * @description
 * @date 2019-05-15 16:08
 */
@Configuration
public class OAuth2 {

    /**
     * @description 资源配置，配置那些资源是需要授权访问，那些是放行的
     * @author xiaomianyang
     * @date 2019-06-25 13:04
     * @param 
     * @return 
     */
    @Configuration
    @EnableResourceServer
    protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter{

        @Autowired
        private CustomAuthenticationEntryPoint customAuthenticationEntryPoint;

        @Autowired
        private CustomLogoutSuccessHandler customLogoutSuccessHandler;

        @Override
        public void configure(HttpSecurity http) throws Exception {
            http.exceptionHandling()
                    .authenticationEntryPoint(customAuthenticationEntryPoint)
                    .and()
                    .logout()
                    .logoutUrl("/oauth/logot")
                    .logoutSuccessHandler(customLogoutSuccessHandler)
                    .and()
                    .authorizeRequests()
                    .antMatchers("/hello/").permitAll()
                    .antMatchers("/secure/**","/html/**").authenticated();
        }
    }

    /**
     * @description 授权服务器配置，配置客户端id，密钥和令牌的过期时间
     * @author xiaomianyang
     * @date 2019-06-25 13:05
     * @param 
     * @return 
     */
    @Configuration
    @EnableAuthorizationServer
    @PropertySource(value ="classpath:config.properties")
    protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

        @Value("${authentication.oauth.clientid}")
        private String clientid;

        @Value("${authentication.oauth.secret}")
        private String secret;

        @Value("${authentication.oauth.tokenValidityInSeconds}")
        private int tokenValidityInSeconds;

        @Autowired
        private DataSource dataSource;

        @Bean
        public TokenStore tokenStore(){
            return new JdbcTokenStore(dataSource);
        }

        @Autowired
        @Qualifier("authenticationManagerBean")
        private AuthenticationManager authenticationManager;

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            endpoints.tokenStore(tokenStore())
                    .authenticationManager(authenticationManager);
        }

        /**
         * @description 配置令牌的作用域和授权方式
         * @author xiaomianyang
         * @date 2019-06-25 13:07
         * @param [clients]
         * @return void
         */
        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.inMemory()
                    .withClient(clientid)
                    .scopes("read","write")
                    .authorities(Authorities.ROLE_ADMIN.name(), Authorities.ROLE_USER.name())
                    .authorizedGrantTypes("password","refresh_token")
                    .secret(secret)
                    .accessTokenValiditySeconds(tokenValidityInSeconds);
        }
    }

}
